home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
prog
/
v16pcx.arj
/
V16PCX.C
next >
Wrap
C/C++ Source or Header
|
1993-05-19
|
7KB
|
336 lines
#include "stdio.h"
#include "process.h"
#include "conio.h"
#include "alloc.h"
#include "dos.h"
#include "graphics.h"
#include "mem.h"
#define VGA 0x0012
#define STRIPSIZE 24
#define pixels2bytes(n) ((n+7)/8)
typedef struct {
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
int xmin,ymin;
int xmax,ymax;
int hres;
int vres;
char palette[48];
char reserved;
char colour_planes;
int bytes_per_line;
int palette_type;
char filler[58];
} PCXHEAD;
ShowPicture(char *p,int width,int depth,int mode,char *palette);
char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
char bittable[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned int screenwide,screendeep,screenbytes;
char *screentable[800];
char *farPtr(char *p,long l);
error(char *s);
UnpackPcxFile(char *p,FILE *fp,int width,int depth,int bytes,int bits,
int winflag);
void init(int mode,char *p);
void deinit(void);
setvgapalette(char *p);
ReadPcxLine(char *p,FILE *fp,int bytes);
egaplane(int n);
main(int argc,char *argv[])
{
PCXHEAD header;
FILE *fp;
char *p;
int width,depth,bytes,bits,winflag,planesize,n=VGA;
/* check for arguments */
if(argc<=1) error("I need a path to a PCX file");
/* attempt to open the file */
if((fp=fopen(argv[1],"rb")) == NULL)
error("Error opening the file");
/* read in the header */
if(fread((char *)&header,1,sizeof(PCXHEAD),fp) != sizeof(PCXHEAD))
error("Error reading the PCX header");
/* check to make sure it's a picture */
if(header.manufacturer != 0x0a)
error("This is not a PCX file");
/* allocate a big buffer */
width = (header.xmax-header.xmin)+1;
depth = (header.ymax-header.ymin)+1;
bytes=header.bytes_per_line;
if(header.bits_per_pixel == 1) bits=header.colour_planes;
else bits=header.bits_per_pixel;
if(header.bits_per_pixel==4 && header.colour_planes==1)
{winflag=1;planesize=1;}
else {winflag=0;planesize=4;}
if(bits < 2 || bits > 4)
error("This file has the wrong number of colours");
if((p=(char *)farmalloc((long)bytes*(long)planesize*(long)depth)) == NULL)
error("Can't allocate memory");
puts("Unpacking file");
/* unpack the file */
if(UnpackPcxFile(p,fp,width,depth,bytes,bits,winflag))
error("Error unpacking the file");
puts("Showing picture");
ShowPicture(p,width,depth,n,header.palette);
free(p);
fclose(fp);
return(0);
}
ShowPicture(char *p,int width,int depth,int mode,char *palette)
{
char *pr;
unsigned int i,w,bytes,linebytes;
init(mode,palette);
bytes=pixels2bytes(width);
linebytes=bytes<<2;
if(width>screenwide) w=pixels2bytes(screenwide);
else w=pixels2bytes(width);
for(i=0;i<screendeep;++i) {
if(i>=depth) break;
pr=farPtr(p,(long)i*(long)linebytes);
egaplane(1);
memcpy(screentable[i],pr,w);
pr+=bytes;
egaplane(2);
memcpy(screentable[i],pr,w);
pr+=bytes;
egaplane(4);
memcpy(screentable[i],pr,w);
pr+=bytes;
egaplane(8);
memcpy(screentable[i],pr,w);
pr+=bytes;
egaplane(15);
}
getch();
deinit();
return(0);
}
/* unpack and display a PCX file... dealing with all the weird ones */
UnpackPcxFile(char *p,FILE *fp,int width,int depth,int bytes,int bits,
int winflag)
{
char *lb,*eb,*pr;
int c,i,k,j,x,linebytes;
/* it's nybbbled, one line is half the width */
if(winflag) {
linebytes=bytes;
bytes=pixels2bytes(width);
} else linebytes=bytes*bits;
/*allocate some scratch buffers */
if((lb=(char *)malloc(bytes<<2)) == NULL) return(1);
if((eb=(char *)malloc(bytes<<2)) == NULL) {
free(lb);
return(1);
}
/* loop through all the strips */
for(i=0;i<depth;++i) {
/* fetch a line */
memset(lb,0,bytes<<2);
if(ReadPcxLine(lb,fp,linebytes)!=linebytes) {
deinit();
free(eb);
free(lb);
return(1);
}
/* if it's nybbled, rework it as planes */
if(winflag) {
memcpy(eb,lb,linebytes);
memset(lb,0,linebytes);
for(j=x=0;j<width;) {
c=eb[x] >> 4;
pr=lb;
for(k=0;k<bits;++k) {
if(c & bittable[k])
pr[j>>3] |= masktable[j & 0x0007];
else
pr[j>>3] &= ~masktable[j & 0x0007];
pr+=bytes;
}
++j;
c=eb[x];
pr=lb;
for(k=0;k<bits;++k) {
if(c & bittable[k])
pr[j>>3] |= masktable[j & 0x0007];
else
pr[j>>3] &= ~masktable[j & 0x0007];
pr+=bytes;
}
++j;
++x;
}
}
/* copy the planes into the strip buffer */
x=0;
for(j=0;j<4;++j) {
memcpy(p+pixels2bytes(width)*j,
lb+x,pixels2bytes(width));
x+=bytes;
}
p=farPtr(p,(long)(pixels2bytes(width)<<2));
}
free(eb);
free(lb);
return(0);
}
/* read and decode a PCX line into p */
ReadPcxLine(char *p,FILE *fp,int bytes)
{
int n=0,c,i;
/* null the buffer */
memset(p,0,bytes);
do {
/* get a key byte */
c=fgetc(fp) & 0xff;
/* if it's a run of bytes field */
if((c & 0xc0) == 0xc0) {
/* and off the high bits */
i=c & 0x3f;
/* get the run byte */
c=fgetc(fp);
/* run the byte */
while(i--) p[n++]=c;
}
/* else just store it */
else p[n++]=c;
} while(n < bytes);
return(n);
}
void init(int mode,char *palette)
/* turn on graphics mode */
{
union REGS r;
int i;
screenwide=640;
screendeep=480;
screenbytes=80;
for(i=0;i<screendeep;++i)
screentable[i]=(char *)MK_FP(0xa000,i*screenbytes);
r.x.ax=mode;
int86(0x10,&r,&r);
setvgapalette(palette);
}
void deinit(void) /* turn off graphics card */
{
union REGS r;
r.x.ax=0x0003;
int86(0x10,&r,&r);
}
/*set the EGA palette to RGB buffer p */
setvgapalette(char *p)
{
union REGS r;
int i;
for(i=0;i<16;++i) {
r.h.dh=(*p++)>>2;
r.h.ch=(*p++)>>2;
r.h.cl=(*p++)>>2;
r.x.ax=0x1010;
r.x.bx=i;
int86(0x10,&r,&r);
}
r.x.bx=0;
for(i=0;i<16;++i) {
r.x.ax=0x1000;
int86(0x10,&r,&r);
r.x.bx+=0x0101;
}
return(0);
}
error(char *s)
{
puts(s);
exit(1);
return(0);
}
char *farPtr(char *p,long l) /* Return a far pointer p + l */
{
unsigned int seg,off;
seg = FP_SEG(p);
off = FP_OFF(p);
seg += (off/16);
off &= 0x000f;
off += (unsigned int)(l & 0x000fL);
seg += (l/16L);
p=(char *)MK_FP(seg,off);
return(p);
}
egaplane(int n) /* set the current display plane */
{
outportb(0x3c4,0x02);
outportb(0x3c5,n);
return(0);
}